#include <iostream>
#include <string>
#include <unistd.h>
#include <pthread.h>
#include <time.h>
#include "RingQueue.hpp"
#include "Task.hpp"

void* Producer(void *args)
{
    Yohifo::RingQueue<Yohifo::Task<int>>* rq = static_cast<Yohifo::RingQueue<Yohifo::Task<int>>*>(args);

    // 运算符集
    std::string opers = "+-*/%";

    while(true)
    {
        // 1.生产商品（通过某种渠道获取数据）
        // 随机获取两个数（可以改为输入）
        int x = rand() % 100;
        int y = rand() % 100;

        // 随机获取一种运算符
        char ops[] = {'+', '-', '*', '/', '%'};
        char op = opers[rand() % opers.size()];

        // 生产商品需要时间
        usleep(10000);

        // 2.将商品推送至阻塞队列中
        // 创建匿名对象，并 Push 入阻塞队列中
        rq->Push(Yohifo::Task<int>(x, y, op));

        std::cout << "Producer 生产了: " << x << " " << y << " " << op << " 构成的对象" << std::endl;
        std::cout << "----------------------------" << std::endl;
    }

    pthread_exit((void*)0);
}

void* Consumer(void *args)
{
    Yohifo::RingQueue<Yohifo::Task<int>>* rq = static_cast<Yohifo::RingQueue<Yohifo::Task<int>>*>(args);

    while(true)
    {        
        // 1.从阻塞队列中获取商品
        Yohifo::Task<int> task;
        rq->Pop(&task);

        // 进行业务处理
        task();

        // 消费商品也需要时间
        usleep(10000);

        std::string ret = task.GetResult();

        // 2.消费商品（结合某种具体业务进行处理）
        std::cout << "Consumer 消费了一个对象，并获得结果: " << ret << std::endl;
        std::cout << "===========================" << std::endl;
    }

    pthread_exit((void*)0);
}

int main()
{
    // 种 种子
    srand((size_t)time(nullptr));

    // 创建一个阻塞队列
    Yohifo::RingQueue<Yohifo::Task<int>>* rq = new Yohifo::RingQueue<Yohifo::Task<int>>;

    // 创建多个线程（生产者、消费者）
    pthread_t pro[10], con[20];

    for(int i = 0; i < 10; i++)
    pthread_create(pro + i, nullptr, Producer, rq);

    for(int i = 0; i < 20; i++)
    pthread_create(con + i, nullptr, Consumer, rq);

    for(int i = 0; i < 10; i++)
    pthread_join(pro[i], nullptr);

    for(int i = 0; i < 20; i++)
        pthread_join(con[i], nullptr);

    delete rq;
    return 0;
}